package com.example.gobang.API;

import com.example.gobang.game.*;
import com.example.gobang.model.UserInfo;
import com.example.gobang.model.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.io.IOException;


@Component
public class GameAPI implements WebSocketHandler {

    @Resource(name = "roomManager")
    RoomManager roomManager;

    @Autowired
    ObjectMapper objectMapper;

    @Autowired
    OnlineUserManager onlineUserManager;

    @Resource
    UserMapper userMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("【GameAPI：：afterConnectionEstablished】连接成功");
//      1、 先获取到User对象并检查检查用户是否登录
        UserInfo userInfo = (UserInfo) session.getAttributes().get("userInfo");
        GameReadyResponse response = new GameReadyResponse();
        if (userInfo == null) {
            System.out.println("【GameAPI：：afterConnectionEstablished】未登录！");
            response.setOk(false);
            response.setReason("你未登录，请重新登录!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

//       2. 检查是否多开
        if (onlineUserManager.getFromGameRoom(userInfo.getUserId()) != null
                || onlineUserManager.getFromGameHall(userInfo.getUserId()) != null) {
            System.out.println("【GameAPI：：afterConnectionEstablished】检查到多开!");
            response.setOk(true);
            response.setMessage("RepeatConnection");
            response.setReason("当前游戏账号已在其他设备登录，请登录其他账号!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        // 3. 把玩家设置成上线状态并发送请求
        onlineUserManager.addGameRoom(userInfo.getUserId(), session);

        // 从用户id 得到房间并且将用户设置为游戏就绪状态并返回响应
        Room room = roomManager.getByUserId(userInfo.getUserId());
        if (room == null) {
            response.setOk(false);
            response.setReason("用户尚未匹配到!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            System.out.println("【GameAPI::afterConnectionEstablished】房间不存在");
            return;
        }

//        4. 由于是对整个 room的玩家位置来竞争 ， 所以这里使用room 来竞争
        synchronized (room) {

//            5. 加入房间并返回响应

            //        将玩家对象1加入到房间中
            if (room.getUserInfo1() == null) {
                System.out.println(userInfo.getUserName() + "加入到room.player1");
                room.setUserInfo1(userInfo);
                room.setWhite(userInfo.getUserId());
//            当前两个玩家还没完全到 所以返回
                return;
            }

//        将玩家对象2 加入到房间中，最终满足房间人数开始分别响应响应
            if (room.getUserInfo2() == null) {
                System.out.println(userInfo.getUserName() + "加入到room.player2");
                room.setUserInfo2(userInfo);
//            分别发送给各自的玩家
                noticeGameReady(room, room.getUserInfo1(), room.getUserInfo2());
                noticeGameReady(room, room.getUserInfo2(), room.getUserInfo1());
                return;
            }
        }

//        6. 特殊情况处理
// 如果房间满了， 这里就需要返回错误的信息
        System.out.println("房间已满，请重新匹配!");
        response.setOk(false);
        response.setReason("房间已满，请重新匹配!");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    private void noticeGameReady(Room room, UserInfo thisUser, UserInfo thatUser) throws IOException {
//        设置响应数据
        GameReadyResponse response = new GameReadyResponse();
        response.setOk(true);
        response.setThisUserId(thisUser.getUserId());
        response.setThatUserId(thatUser.getUserId());
        response.setMessage("gameReady");
        response.setRoomId(room.getRoomId());
        response.setWhiteUser(room.getWhite());
        response.setReason("");
        WebSocketSession socketSession = onlineUserManager.getFromGameRoom(thisUser.getUserId());
        socketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
//        处理落子请求
//        1. 获取对象并获取房间
        UserInfo userInfo = (UserInfo) session.getAttributes().get("userInfo");
        if (userInfo == null) {
            System.out.println("【GameAPI::handleMessage】未登录!");
            return;
        }
        Room room = roomManager.getByUserId(userInfo.getUserId());
        if (room == null) {
            System.out.println("gameAPI::handleMessage:" + room);
            return;
        }

        Object payload = message.getPayload();

//        通过房间接收落子请求
        room.putChess(payload);


    }

    @Override
    public void handleTransportError(WebSocketSession existSession, Throwable exception) throws Exception {
        System.out.println("【GameAPI：：handleTransportError】连接异常");

        exist(existSession);
    }


    @Override
    public void afterConnectionClosed(WebSocketSession existSession, CloseStatus closeStatus) throws Exception {
        System.out.println("【GameAPI：：afterConnectionClosed】连接关闭");

        exist(existSession);
    }

    private void exist(WebSocketSession existSession) throws IOException {
        //        1.通过对象来获取在线状态
        UserInfo userInfo = (UserInfo) existSession.getAttributes().get("userInfo");
        if (userInfo == null) {
            System.out.println(userInfo.getUserName() + "未登录!");
            return;
        }
//        如果相同说明在Map中就退出在线状态
        WebSocketSession onlineSession = onlineUserManager.getFromGameRoom(userInfo.getUserId());
        if (onlineSession == existSession) {
            // 防止多开的情况， 有可能会把在线的玩家一并带走
            onlineUserManager.exitGameRoom(userInfo.getUserId());
        }


        // 通知对手，他赢了
        // 1. 通过房间信息来获取对手信息
        Room room = roomManager.getByUserId(userInfo.getUserId());
        UserInfo thatUser = room.getUserInfo1().getUserId() == userInfo.getUserId()
                ? room.getUserInfo2() : room.getUserInfo1();

        WebSocketSession socketSession = onlineUserManager.getFromGameRoom(thatUser.getUserId());
        if (socketSession == null) {
            System.out.println("玩家二也退出房间，游戏退出，没有赢家!");
            return;
        }

        GameResponse response = new GameResponse();
        System.out.println("对手已掉线，你赢了!");
        response.setMessage("opponentExit");
        response.setWinner(thatUser.getUserId());
        response.setUserId(thatUser.getUserId());

//         计算得分
        userMapper.updateWinner(thatUser);
        userMapper.updateLoser(userInfo);
        socketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }


    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
}
